"""
Python文件读写模式详解

本节课我们将详细介绍Python不同的文件读写模式，了解它们的区别和应用场景。
文件读写模式决定了我们如何与文件交互，选择合适的模式可以提高代码效率和可读性。
"""

print("=" * 60)
print("Python文件读写模式详解")
print("=" * 60)

# =============== 1. 文件读写模式概览 ===============

print("\n1. 文件读写模式概览")
print("-" * 40)

print("""
Python文件读写模式一览表：

模式     描述                                                   是否常用
-----   ----------------------------------------------------   -------
r       只读模式（默认）。文件必须存在，否则报错。               【常用】
w       写入模式。如果文件存在，清空内容；不存在则创建。         【常用】
a       追加模式。从文件末尾追加内容；不存在则创建。             【常用】
r+      读写模式。文件必须存在，可读可写。
w+      读写模式。清空内容或创建新文件，可读可写。
a+      追加读写模式。从末尾追加，可读可写。
rb      二进制只读模式。处理图片、音频等二进制文件。             【常用】
wb      二进制写入模式。处理二进制文件写入。多用于下载文件。      【常用】
ab      二进制追加模式。追加二进制数据。

【常用】标记表示日常编程中最为常用的模式，是必须掌握的基础。
""")

# 创建示例文件目录
import os  # noqa: E402

test_dir = "file_mode_examples"
if not os.path.exists(test_dir):
    os.makedirs(test_dir)

# =============== 2. 只读模式（r）===============

print("\n2. 只读模式（r）【常用】")
print("-" * 40)

# 创建一个用于演示的文本文件
demo_file_path = os.path.join(test_dir, "demo_text.txt")

# 先创建一个示例文件
with open(demo_file_path, "w") as file:
    file.write("第一行：读取文件测试\n")
    file.write("第二行：展示只读模式\n")
    file.write("第三行：这是最后一行内容")

print("""
r模式特点：
- 只能读取，不能写入
- 文件必须已经存在，否则报错
- 文件指针起始位置在文件开头
- 是默认模式，open('file.txt') 等同于 open('file.txt', 'r')
""")

print("示例 - 读取整个文件:")
try:
    with open(demo_file_path, "r") as file:
        content = file.read()
        print(f"文件内容:\n{content}")
except FileNotFoundError:
    print(f"错误：文件 {demo_file_path} 不存在")

print("\n示例 - 尝试用r模式写入（会引发错误）:")
try:
    with open(demo_file_path, "r") as file:
        file.write("这行内容不会被写入")  # 这会引发错误
except IOError as e:
    print(f"预期的错误：{e}")

# =============== 3. 写入模式（w）===============

print("\n3. 写入模式（w）【常用】")
print("-" * 40)

write_file_path = os.path.join(test_dir, "write_example.txt")

print("""
w模式特点：
- 只用于写入，不能读取
- 如果文件已存在，会先清空文件内容
- 如果文件不存在，会创建新文件
- 文件指针起始位置在文件开头
""")

print("示例 - 创建并写入新文件:")
with open(write_file_path, "w") as file:
    file.write("第一行：这是写入的新内容\n")
    file.write("第二行：使用w模式写入\n")
    file.write("第三行：文件会被创建或内容会被覆盖")

print(f"已创建并写入文件：{write_file_path}")

# 显示文件内容
with open(write_file_path, "r") as file:
    print("\n文件内容:")
    print(file.read())

print("\n示例 - 覆盖已有内容:")
with open(write_file_path, "w") as file:
    file.write("这是全新的内容，之前的内容已被覆盖！")

# 显示文件内容
with open(write_file_path, "r") as file:
    print("\n覆盖后的文件内容:")
    print(file.read())

# =============== 4. 追加模式（a）===============

print("\n4. 追加模式（a）【常用】")
print("-" * 40)

append_file_path = os.path.join(test_dir, "append_example.txt")

print("""
a模式特点：
- 用于追加内容，不能读取
- 如果文件已存在，从文件末尾开始追加
- 如果文件不存在，会创建新文件
- 文件指针起始位置在文件末尾
多用于日志的追加记录。
""")

# 创建或清空文件用于演示
with open(append_file_path, "w") as file:
    file.write("原始内容第一行\n")
    file.write("原始内容第二行\n")

print("示例 - 追加内容到文件:")
with open(append_file_path, "a") as file:
    file.write("这是追加的第一行\n")
    file.write("这是追加的第二行\n")

# 显示文件内容
with open(append_file_path, "r") as file:
    print("\n追加后的文件内容:")
    print(file.read())

# =============== 5. 读写模式（r+）===============

print("\n5. 读写模式（r+）")
print("-" * 40)

rplus_file_path = os.path.join(test_dir, "rplus_example.txt")

# 先创建文件
with open(rplus_file_path, "w") as file:
    file.write("原始内容第一行\n")
    file.write("原始内容第二行\n")
    file.write("原始内容第三行\n")

print("""
r+模式特点：
- 可以读取也可以写入
- 文件必须已经存在，否则报错
- 文件指针起始位置在文件开头
- 写入时会先将指针移到文件末尾，然后写入新内容
""")

print("示例 - 先读后写:")
with open(rplus_file_path, "r+") as file:
    # 读取前两行
    print("读取前两行:")
    print(file.readline().strip())
    print(file.readline().strip())

    # 当前指针位置在第二行末尾，写入时会自动跳转到文件末尾开始写
    file.write("这是在r+模式下写入的内容\n")

# 显示文件内容
with open(rplus_file_path, "r") as file:
    print("\n操作后的文件内容:")
    print(file.read())

# =============== 6. 写入读取模式（w+）===============

print("\n6. 写入读取模式（w+）")
print("-" * 40)

wplus_file_path = os.path.join(test_dir, "wplus_example.txt")

print("""
w+模式特点：
- 可以读取也可以写入
- 如果文件已存在，会先清空文件内容
- 如果文件不存在，会创建新文件
- 文件指针起始位置在文件开头
- 写入后需要移动指针才能读取刚写入的内容
""")

print("示例 - 写入后读取:")
with open(wplus_file_path, "w+") as file:
    # 写入内容
    file.write("第一行：w+模式示例\n")
    file.write("第二行：写入内容\n")
    file.write("第三行：再读取内容\n")

    # 写入后指针在文件末尾，需要移动指针到文件开头才能读取
    file.seek(0)  # 移动指针到文件开头

    # 读取内容
    print("\n写入后移动指针到文件开头再读取:")
    print(file.read())

# =============== 7. 追加读取模式（a+）===============

print("\n7. 追加读取模式（a+）")
print("-" * 40)

aplus_file_path = os.path.join(test_dir, "aplus_example.txt")

# 预先创建文件
with open(aplus_file_path, "w") as file:
    file.write("原始内容第一行\n")
    file.write("原始内容第二行\n")

print("""
a+模式特点：
- 可以读取也可以写入
- 如果文件已存在，写入操作从文件末尾开始追加
- 如果文件不存在，会创建新文件
- 文件指针起始位置在文件末尾（为追加做准备）
- 需要移动指针才能读取文件内容
""")

print("示例 - 先读取再追加:")
with open(aplus_file_path, "a+") as file:
    # 初始指针在文件末尾，需要移动到开头才能读取
    file.seek(0)  # 移动指针到文件开头

    # 读取原有内容
    content = file.read()
    print(f"原有内容:\n{content}")

    # 追加新内容（不需要移动指针，a+模式下写入总是追加到末尾）
    file.write("这是a+模式追加的新内容第一行\n")
    file.write("这是a+模式追加的新内容第二行\n")

# 显示最终文件内容
with open(aplus_file_path, "r") as file:
    print("\n操作后的文件内容:")
    print(file.read())

# =============== 8. 二进制模式 ===============

print("\n8. 二进制模式（rb, wb, ab）")
print("-" * 40)

binary_file_path = os.path.join(test_dir, "binary_example.bin")

print("""
二进制模式特点：
- rb：二进制只读模式【常用】，常用于读取图像、音频等非文本文件
- wb：二进制写入模式，写入二进制数据，会清空原有内容
- ab：二进制追加模式，在末尾追加二进制数据，多用于下载文件中的断点续传
- 读写的是字节而非字符，处理结果是bytes类型而非str类型
""")

print("示例 - 创建和读取二进制文件:")
# 写入二进制数据
with open(binary_file_path, "wb") as file:
    # 写入一些二进制数据
    # 这里的\x是python的转义字符，表示一个十六进制的ASCII码
    file.write(b"\x48\x65\x6c\x6c\x6f")  # "Hello"的ASCII码
    file.write(b"\x2c\x20")  # ", "的ASCII码
    file.write(b"\x57\x6f\x72\x6c\x64")  # "World"的ASCII码

# 读取二进制数据
with open(binary_file_path, "rb") as file:
    binary_data = file.read()
    print(f"读取的二进制数据: {binary_data}")
    print(f"转换为字符串: {binary_data.decode('ascii')}")

print("\n示例 - 追加二进制数据:")
with open(binary_file_path, "ab") as file:
    file.write(b"\x21")  # "!"的ASCII码

# 读取更新后的二进制数据
with open(binary_file_path, "rb") as file:
    binary_data = file.read()
    print(f"追加后的二进制数据: {binary_data}")
    print(f"转换为字符串: {binary_data.decode('ascii')}")


## --- 删除示例文件 ---
import shutil  # noqa: E402

delete_demo = True
if delete_demo and os.path.exists(test_dir):
    shutil.rmtree(test_dir)


# =============== 9. 文件模式选择指南 ===============

print("\n9. 文件模式选择指南")
print("-" * 40)

print("""
如何选择合适的文件模式？

1. 基本原则：
   - 仅需读取数据 → 'r'模式
   - 需要写入并清空原内容 → 'w'模式
   - 需要在末尾添加内容 → 'a'模式
   - 处理二进制文件 → 添加'b'后缀（rb, wb, ab）

2. 常见使用场景：
   - 配置文件读取 → 'r'
   - 日志文件记录 → 'a'
   - 数据导出覆盖 → 'w'
   - 图像/音频处理 → 'rb'/'wb'
   - 需要同时读写但不覆盖 → 'r+'（谨慎使用）
   - 需要同时读写且覆盖 → 'w+'（谨慎使用）
   - 需要追加并读取 → 'a+'（谨慎使用）

3. 最佳实践：
   - 尽量使用单一用途的模式（r, w, a, rb, wb, ab）
   - 避免使用复合模式（r+, w+, a+），除非有明确需求
   - 使用复合模式时要特别注意文件指针位置
   - 使用二进制模式处理非文本文件
   - 始终使用with语句自动管理文件资源
""")

# =============== 总结 ===============

print("\n" + "=" * 60)
print("总结：文件读写模式")
print("-" * 40)
print("""
1. 【必须掌握】的基础模式：
   - r：只读模式，最常用于读取数据
   - w：写入模式，最常用于覆盖写入
   - a：追加模式，最常用于日志记录
   - rb：二进制读取，最常用于处理媒体文件
   - wb：二进制写入，最常用于保存下载的文件

2. 文件模式的本质是定义：
   - 文件指针的初始位置
   - 允许的操作（读/写/追加）
   - 文件不存在时的行为（创建/报错）
   - 数据处理方式（文本/二进制）

3. 在AI开发中的应用：
   - 读取训练数据集 → r模式
   - 保存模型结果 → w模式
   - 记录训练日志 → a模式
   - 处理图像数据 → rb/wb模式
""")

print("\n无论使用哪种模式，都建议使用with语句自动管理文件资源，确保文件正确关闭。")
print("=" * 60)
